

function renderMineField(m, n, mineNums) {
    let tableEl = document.querySelector("#mine-field");
    tableEl.innerHTML = "";

    let gameState = {
        remaining: null,
        timming: null,     //游戏开始与否
        cells: null,
        gameOver: false,
    }

    
   



    this.m = m;
    this.n = n;
    this.mineNums = mineNums;
    clearInterval(gameState.intervalID);




    let cells = [];


    for (let i = 0; i < m; i++) {
        let trEl = document.createElement("tr");
        let row = [];
        for (let j = 0; j < n; j++) {
            let tdEl = document.createElement("td");
            let cellEl = document.createElement('div');
            cellEl.className = "cell unclear";

            cellEl.onclick = function () {
                if (gameState.gameOver) {
                    return;
                }
                handleClick(m, n, mineNums, gameState, i, j);          //点击事件
            };
            cellEl.oncontextmenu = function (event) {
                if (gameState.gameOver) {
                    return;
                }
                handleFlagging(m, n, mineNums, gameState, i, j);   //右击标旗
                event.stopPropagation();
                event.preventDefault();
            };

            tdEl.append(cellEl);
            row.push({
                mined: false,
                el: cellEl,
            });
            trEl.append(tdEl);

        }


        cells.push(row);
        tableEl.append(trEl);




    }

    gameState.cells = cells;

    let minefields = rendomMineFieldNo(m, n, mineNums);
    //let minefields =[49, 25, 30, 56, 31, 57, 18, 52, 40, 11]



    for (let cellNo of minefields) {
        let rowNo = Math.floor(cellNo / n);
        let colNo = cellNo % n;
        let cell = cells[rowNo][colNo];
        cell.mined = true;
        let mineSpan = document.createElement('span');
        mineSpan.className = "mine";

        cell.el.append(mineSpan);            //布雷

    }

    checkAmbedianMineCounts(m, n, mineNums, gameState)



    let messageEl = document.querySelector(".game-info > .message");
    messageEl.innerText = "🚩modeON";
    messageEl.onclick = function () {     //重新开始
        let tableEl = document.querySelector("#mine-field");
        tableEl.innerHTML = "";
        clearInterval(gameState.intervalID);
        gameState.timming = 0;
        renderMineField(m, n, mineNums);

    }

}





let directions = [
    [-1, -1], [-1, 0], [-1, +1],
    [0, +1],
    [+1, +1], [+1, 0], [+1, -1],
    [0, -1]
]

function checkAmbedianMineCounts(m, n, mineNums, gameState) {         //计算周边的雷的数量
    for (let rowIdx = 0; rowIdx < m; rowIdx++) {

        for (let colIdx = 0; colIdx < n; colIdx++) {
            let cell = gameState.cells[rowIdx][colIdx];
            if (cell.mined) {
                continue
            }
            let mineCount = 0;
            for (let [drow, dcol] of directions) {
                let newRowIdx = rowIdx + drow, newColIdx = colIdx + dcol;
                if (newRowIdx < 0 || newRowIdx >= m ||
                    newColIdx < 0 || newColIdx >= n) {
                    continue
                }

                if (gameState.cells[newRowIdx][newColIdx].mined) {
                    mineCount += 1;
                }
            }
            if (mineCount > 0) {
                let countSpan = document.createElement('span');
                countSpan.className = "mine-count";
                countSpan.innerText = `${mineCount}`;

                countSpan.classList.add(`n${mineCount}`);
                cell.el.append(countSpan);

            }


            cell.mineCount = mineCount;


        }
    }

}


function rendomMineFieldNo(m, n, mineNums) {       //随机生成雷的算法
    console.assert(mineNums <= m * n);
    let mines = [];
    let fieldNo;
    for (let i = 0; i < mineNums; i++) {
        while (true) {
            fieldNo = Math.floor(Math.random() * m * n);
            if (!mines.includes(fieldNo)) {
                break;
            }

        }

        mines.push(fieldNo);
    }
    return mines;
}



function handleClick(m, n, mineNums, gameState, rowIdx, colIdx) {
    
    if (gameState.timming === null) {
        clearInterval(gameState.intervalID);
        startGame(m, n, mineNums, gameState);
    }

    let cell = gameState.cells[rowIdx][colIdx];
    if (cell.mined) {
        explode(m, n, mineNums, gameState, rowIdx, colIdx);
    } else if (cell.mineCount == 0) {
        spreadSafefield(m, n, mineNums, gameState, rowIdx, colIdx);    //点击空白展开
    } else if (cell.mineCount > 0) {       //点击数字展开
        let cell = gameState.cells[rowIdx][colIdx];
        if (!cell.spread) {
            cell.spreaded = true;
            cell.el.classList.remove("unclear");
            cell.el.classList.add("spreaded");
        }
  
    }
    if (checkSuccess(m, n, mineNums, gameState)) {
        gameSuccess(m, n, mineNums, gameState)
    }
    // console.log(gameState.cells[rowIdx][colIdx])
}


function startGame(m, n, mineNums, gameState) {
    
    let messageEl = document.querySelector(".game-info > .message");
    messageEl.innerText = "🚩Onging";

    gameState.remaining = mineNums;
    let remainingEl = document.querySelector(".game-info >.remaining");
    remainingEl.innerHTML = `<span>Mine:
                                    ${gameState.remaining}</span>`;     //计算剩余雷数

    let timerEl = document.querySelector(".game-info >.timer");
    let secondsEl = document.createElement("span");
    timerEl.append(secondsEl);
    gameState.timming = 0;
    timerEl.innerText = `Time:
                          ${gameState.timming}s`;

    gameState.intervalID = setInterval(function () {
        gameState.timming += 1;
        timerEl.innerHTML = `<span>Time:
                                     ${gameState.timming}s</span>`;

    }, 1000);                          //计时器




}






function checkSuccess(m, n, mineNums, gameState) {         //判定游戏通关
    let unspreadCount = 0;
    for (let rowIdx = 0; rowIdx < m; rowIdx++) {
        for (let colIdx = 0; colIdx < n; colIdx++) {
            let cell = gameState.cells[rowIdx][colIdx];
            if (cell.flag) {
                continue;
            }

            if (!cell.spreaded) {
                unspreadCount += 1;

            }
        }
    }
    return gameState.remaining === unspreadCount;

}


function explode(m, n, mineNums, gameState, rowIdx, colIdx) {        //雷爆炸

    for (let rowIdx = 0; rowIdx < m; rowIdx++) {
        for (let colIdx = 0; colIdx < n; colIdx++) {        //遍历
            let cell = gameState.cells[rowIdx][colIdx];
            if (cell.mined) {
                cell.exploded = true;
                cell.el.classList.add("exploded");

            } else {
                cell.el.classList.add("exploded");
                cell.el.classList.add("spreaded");

            }
            cell.el.classList.remove("unclear");
        }
    }
    clearInterval(gameState.intervalID);     //停止计时
    let messageEl = document.querySelector(".game-info > .message");
    messageEl.innerText = "🚩modeOFF";
    gameState.gameOver = true;

}

function gameSuccess(m, n, mineNums, gameState) {       //游戏通关
    for (let rowIdx = 0; rowIdx < m; rowIdx++) {
        for (let colIdx = 0; colIdx < n; colIdx++) {        //遍历
            let cell = gameState.cells[rowIdx][colIdx];
            if (cell.mined) {
                cell.exploded = true;
                cell.el.classList.add("success");
            } else {
                cell.el.classList.add("success");
                cell.el.classList.add("spreaded");

            }
        }
    }
    clearInterval(gameState.intervalID);     //停止计时
    let messageEl = document.querySelector(".game-info > .message");
    messageEl.innerText = "🚩Victory";
    messageEl.classList.add("success");

    gameState.gameOver = true;



}

function handleFlagging(m, n, mineNums, gameState, rowIdx, colIdx) {   //右击标旗
    if (gameState.timming === null) {
        clearInterval(gameState.intervalID);
        startGame(m, n, mineNums, gameState);
    }
    let cell = gameState.cells[rowIdx][colIdx];
    if (cell.spreaded) {
        return
    }
    setFlag(cell, !cell.flag);
    if (cell.flag) {
        gameState.remaining -= 1;      //标旗雷的剩余数-1

    } else {
        gameState.remaining += 1;      //取消标旗雷的剩余数-1

    } let remainingEl = document.querySelector(".game-info >.remaining > span");
    remainingEl.innerText = `Mine:
                             ${gameState.remaining}`;

    if (checkSuccess(m, n, mineNums, gameState)) {
        gameSuccess(m, n, mineNums, gameState)
    }

}

function setFlag(cell, flag) {       //标旗
    if (flag) {
        cell.flag = true;
        cell.el.innerHTML = `<span class="flag">🚩</span>`;
    } else {
        cell.flag = false;
        if (cell.mined) {
            cell.el.innerHTML = `<span class="mine">💣</span>`;
        } else if (cell.mineCount > 0) {
            cell.el.innerHTML = `<span class="mine-count n${cell.mineCount}">${cell.mineCount}</span>`;
        } else {
            cell.el.innerHTML = "";
        }

    }
}




function spreadSafefield(m, n, mineNums, gameState, rowIdx, colIdx) {    //展开空白区域
    let cell = gameState.cells[rowIdx][colIdx];
    if (!cell.spread) {
        cell.spreaded = true;
        cell.el.classList.remove("unclear");
        cell.el.classList.add("spreaded");
        if (cell.flag) {
            setFlag(cell, false);
        }
    }
    for (let [drow, dcol] of directions) {
        let newRowIdx = rowIdx + drow, newColIdx = colIdx + dcol;
        if (newRowIdx < 0 || newRowIdx >= m ||
            newColIdx < 0 || newColIdx >= n) {
            continue
        }
        let cell = gameState.cells[newRowIdx][newColIdx];
        if (cell.spreaded) {
            continue;
        }
        if (!cell.spreaded && cell.mineCount == 0) {
            spreadSafefield(m, n, mineNums, gameState, newRowIdx, newColIdx);   //递归
        }
        cell.spreaded = true;
        cell.el.classList.remove("unclear");
        cell.el.classList.add("spreaded");

        if (cell.flag) {
            setFlag(cell, false);
        }
    }


}






function selectEasyMode() {
   
    renderMineField(8, 8, 10);
    

}
function selectMediumMode() {
    renderMineField(12, 12, 25);

}
function selectHardMode() {
    renderMineField(16, 16, 40);
}





renderMineField(12, 12, 25);